﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.CApAPPPlanCommand
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using DnProcessSimulateCommands.AutomaticPathPlanner;
using DnProcessSimulateCommands.AutomaticPathPlanner.Planner;
using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Tecnomatix.Engineering;


namespace DnProcessSimulateCommands;

public class CApAPPPlanCommand : CApAPPPlanCommandBase
{
  private System.Windows.Forms.Timer m_timer;
  private Stopwatch m_elapsedTimer;
  private long m_lastRefreshTime;
  private List<CApAPPSubTask> m_allSubtasksToPlan;
  private List<CApAPPSegmentPlanCommand> m_allThreadedPlanCommand;
  private List<Thread> m_allPlanningThreads;
  private List<Thread> m_runningPlanningThreads;
  private List<CApAPPSegmentPlanCommand> m_runningThreadedPlanCommand;
  private List<CApAPPWaypoint> m_waypointSavedAfterPreProcess;
  private List<CApAPPSegmentPreProcessingCommand> m_allThreadedPreProcessingPlanCommand;
  private List<Thread> m_allPreProcessingPlanningThreads;
  private CApAPPOptimizeCycleTimeCommand m_subCycleTimeOpt;
  private CApAPPMagnetPoint m_magnetPoint;
  private int m_currentSubTaskIndex;
  private bool m_planningWasSkipped;
  private bool m_atLeastOneSuccess;
  private bool m_atLeastOneError;
  private bool m_optimize;
  private bool m_useMultithreadPlanning;
  private int m_maxParallelPlanning;
  private bool m_preProcessing;
  private bool m_preProcessinRuning;
  private bool m_mustShowLastAddedPosition;

  public CApAPPPlanCommand(
    List<CApAPPTask> i_tasks,
    KiAppPathPlanningParamsEx i_pathPlanningParams,
    bool i_activateOptimization,
    bool i_preProcessing)
    : base(i_tasks, i_pathPlanningParams)
  {
    this.m_timer = new System.Windows.Forms.Timer();
    this.m_elapsedTimer = new Stopwatch();
    this.m_lastRefreshTime = 0L;
    this.m_subCycleTimeOpt = (CApAPPOptimizeCycleTimeCommand) null;
    this.m_timer.Interval = 250;
    this.m_maxParallelPlanning = 54;
    this.m_allSubtasksToPlan = this.GetAllSubtasksToPlan();
    this.PlanningWasCancelled = false;
    this.m_planningWasSkipped = false;
    this.m_atLeastOneSuccess = false;
    this.m_optimize = i_activateOptimization;
    this.m_currentSubTaskIndex = -1;
    this.m_preProcessing = i_preProcessing;
    this.m_allThreadedPlanCommand = new List<CApAPPSegmentPlanCommand>();
    this.m_allPlanningThreads = new List<Thread>();
    this.m_allThreadedPreProcessingPlanCommand = new List<CApAPPSegmentPreProcessingCommand>();
    this.m_allPreProcessingPlanningThreads = new List<Thread>();
    this.m_runningPlanningThreads = new List<Thread>();
    this.m_runningThreadedPlanCommand = new List<CApAPPSegmentPlanCommand>();
    this.m_useMultithreadPlanning = false;
    if (this.m_useMultithreadPlanning)
      this.m_timer.Tick += new EventHandler(this.OnMTTimer);
    else
      this.m_timer.Tick += new EventHandler(this.OnTimer);
    this.m_magnetPoint = (CApAPPMagnetPoint) null;
    this.m_mustShowLastAddedPosition = false;
  }

  internal override void UpdateSubTaskToPlan()
  {
    this.m_allSubtasksToPlan = this.GetAllSubtasksToPlan();
  }

  protected virtual List<CApAPPSubTask> GetAllSubtasksToPlan()
  {
    List<CApAPPSubTask> allSubtasksToPlan = new List<CApAPPSubTask>();
    for (int index = 0; index < this.TasksToPlan.Count; ++index)
    {
      for (int i_index = 0; i_index < this.TasksToPlan[index].CountSubTasks(); ++i_index)
      {
        if (this.TasksToPlan[index].SubTask(i_index).IsToPlan())
          allSubtasksToPlan.Add(this.TasksToPlan[index].SubTask(i_index));
      }
    }
    return allSubtasksToPlan;
  }

  internal CApAPPSegmentPreProcessingCommand DoCreateThreadPreProcessingCommand(
    CApAPPSubTask i_subtask)
  {
    return new CApAPPSegmentPreProcessingCommand(i_subtask);
  }

  internal virtual CApAPPSegmentPlanCommand DoCreateThreadCommand(
    CApAPPSubTask i_subtask,
    KiAppPathPlanningParamsEx i_pathPlanningParams,
    bool i_optimize)
  {
    return new CApAPPSegmentPlanCommand(i_subtask, i_pathPlanningParams, i_optimize);
  }

  protected override bool DoStart(
    ref CApAPPPlanCommandBase.PlanSuccessEventArgs errEvtArgs)
  {
    bool flag1 = false;
    bool flag2;
    if (!this.m_useMultithreadPlanning)
    {
      this.m_preProcessinRuning = this.m_preProcessing;
      flag2 = this.StartNextPathPlanning(ref flag1);
      if (!flag2 && this.m_preProcessinRuning)
      {
        this.EndPreProcessingPlanning(false, ref flag1);
        flag2 = true;
      }
    }
    else
    {
      flag2 = this.StartAllPathPlannings();
      if (flag2)
        this.LaunchThreads();
    }
    if (!flag2 | flag1)
      this.NotifyEndPlanning();
    return flag2;
  }

  public bool LaunchThreads()
  {
    int num = Math.Min(this.m_maxParallelPlanning, this.m_allPlanningThreads.Count);
    for (int index = 0; index < num; ++index)
    {
      this.m_runningPlanningThreads.Add(this.m_allPlanningThreads[index]);
      this.m_runningThreadedPlanCommand.Add(this.m_allThreadedPlanCommand[index]);
      this.m_runningPlanningThreads[index].Start();
    }
    this.m_currentSubTaskIndex = num - 1;
    return true;
  }

  public bool StartAllPathPlannings()
  {
    bool flag1 = true;
    for (int index = 0; index < this.m_allSubtasksToPlan.Count; ++index)
    {
      CApAPPSegmentPlanCommand threadCommand = this.DoCreateThreadCommand(this.m_allSubtasksToPlan[index], this.PathPlanningParams, this.m_optimize);
      bool flag2 = threadCommand.StartPlanning();
      this.m_allThreadedPlanCommand.Add(threadCommand);
      if (flag2)
        this.m_allPlanningThreads.Add(new Thread(new ThreadStart(threadCommand.OnStartThread))
        {
          Priority = ThreadPriority.BelowNormal
        });
      flag1 &= flag2;
    }
    this.m_timer.Start();
    this.m_elapsedTimer.Start();
    this.UpdatePlanSuccesses();
    return flag1;
  }

  public bool StartNextPathPlanning(ref bool o_trackEndReached)
  {
    bool flag = true;
    ++this.m_currentSubTaskIndex;
    o_trackEndReached = false;
    if (this.m_currentSubTaskIndex >= this.m_allSubtasksToPlan.Count)
    {
      o_trackEndReached = true;
    }
    else
    {
      if (this.m_preProcessinRuning)
      {
        flag = false;
        while (!flag && this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count)
        {
          CApAPPSubTask i_subtask = this.m_allSubtasksToPlan[this.m_currentSubTaskIndex];
          this.m_planningWasSkipped = false;
          this.m_allThreadedPreProcessingPlanCommand.Add(this.DoCreateThreadPreProcessingCommand(i_subtask));
          flag = this.m_allThreadedPreProcessingPlanCommand[this.m_allThreadedPreProcessingPlanCommand.Count - 1].StartPlanning();
          this.UpdatePlanSuccesses();
          if (flag)
          {
            this.m_timer.Start();
            this.m_elapsedTimer.Start();
            this.StartPreProcessingPlanningThread();
            this.UpdatePlanSuccesses();
          }
          else
            ++this.m_currentSubTaskIndex;
        }
      }
      else
      {
        flag = false;
        while (!flag && this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count)
        {
          CApAPPWaypointPlanSuccess waypointPlanSuccess = this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].LastWaypoint().WaypointPlanSuccess;
          while (this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count && waypointPlanSuccess == CApAPPWaypointPlanSuccess.PreProcessingSuccess)
          {
            CApAPPSegmentPlanCommand threadCommand = this.DoCreateThreadCommand(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex], this.PathPlanningParams, this.m_optimize);
            threadCommand.IsPlanned(false);
            this.m_allThreadedPlanCommand.Add(threadCommand);
            ++this.m_currentSubTaskIndex;
            if (this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count)
              waypointPlanSuccess = this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].LastWaypoint().WaypointPlanSuccess;
          }
          if (this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count)
          {
            CApAPPSubTask i_subtask = this.m_allSubtasksToPlan[this.m_currentSubTaskIndex];
            this.m_planningWasSkipped = false;
            this.m_allThreadedPlanCommand.Add(this.DoCreateThreadCommand(i_subtask, this.PathPlanningParams, this.m_optimize));
            flag = this.m_allThreadedPlanCommand[this.m_allThreadedPlanCommand.Count - 1].StartPlanning();
            this.UpdatePlanSuccesses();
            if (flag)
            {
              this.m_timer.Start();
              this.m_elapsedTimer.Start();
              this.StartPlanningThread();
              this.UpdatePlanSuccesses();
            }
            else
            {
              this.m_atLeastOneError = true;
              ++this.m_currentSubTaskIndex;
            }
          }
        }
      }
      if (this.m_currentSubTaskIndex >= this.m_allSubtasksToPlan.Count)
        o_trackEndReached = true;
    }
    return flag;
  }

  private void StartPreProcessingPlanningThread()
  {
    if (this.m_allPreProcessingPlanningThreads.Count > 0 && this.m_allPreProcessingPlanningThreads[this.m_allPreProcessingPlanningThreads.Count - 1] != null)
      this.m_allPreProcessingPlanningThreads[this.m_allPreProcessingPlanningThreads.Count - 1].Join();
    this.m_allPreProcessingPlanningThreads.Add(new Thread(new ThreadStart(this.m_allThreadedPreProcessingPlanCommand[this.m_allThreadedPreProcessingPlanCommand.Count - 1].OnStartThread)));
    this.m_allPreProcessingPlanningThreads[this.m_allPreProcessingPlanningThreads.Count - 1].Priority = ThreadPriority.Lowest;
    this.m_allPreProcessingPlanningThreads[this.m_allPreProcessingPlanningThreads.Count - 1].Start();
  }

  private void StartPlanningThread()
  {
    if (this.m_allPlanningThreads.Count > 0 && this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1] != null)
      this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1].Join();
    this.m_allPlanningThreads.Add(new Thread(new ThreadStart(this.m_allThreadedPlanCommand[this.m_allThreadedPlanCommand.Count - 1].OnStartThread)));
    this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1].Priority = ThreadPriority.Lowest;
    this.m_allPlanningThreads[this.m_allPlanningThreads.Count - 1].Start();
  }

  public int CountPlanSubTasks()
  {
    int num = 0;
    for (int index = 0; index < this.TasksToPlan.Count; ++index)
      num += this.TasksToPlan[index].CountSubTasksToPlan();
    return num;
  }

  public override int RetrieveIndexSubProblemFromWaypoint(CApAPPWaypoint i_wp)
  {
    return this.RetrieveIndexSubTaskFromWaypoint(i_wp);
  }

  public override int CountSubProblems() => this.CountPlanSubTasks();

  public int RetrieveIndexSubTaskFromWaypoint(CApAPPWaypoint i_wp)
  {
    int num1 = 0;
    for (int index = 0; index < this.TasksToPlan.Count; ++index)
    {
      int num2 = this.TasksToPlan[index].RetrieveSubTaskIndexFromWaypoint(i_wp);
      if (num2 == -1)
      {
        num1 += this.TasksToPlan[index].CountSubTasksToPlan();
      }
      else
      {
        num1 += num2;
        break;
      }
    }
    return num1;
  }

  public void PlanNames(ref List<string> o_names)
  {
    o_names = new List<string>();
    for (int index = 0; index < this.TasksToPlan.Count; ++index)
    {
      for (int i_index = 0; i_index < this.TasksToPlan[index].CountSubTasksToPlan(); ++i_index)
      {
        string str = ((ITxObject) this.TasksToPlan[index].Operation).Name + " : " + this.TasksToPlan[index].SubTaskToPlan(i_index).Name();
        o_names.Add(str);
      }
    }
  }

  public override void CancelPlanning(int i_subtaskRank)
  {
    this.m_planningWasSkipped = true;
    if (this.m_allThreadedPlanCommand.Count > i_subtaskRank)
    {
      this.m_allThreadedPlanCommand[i_subtaskRank].Cancel();
      this.UpdateWaypointPlanSuccess(i_subtaskRank);
    }
    if (this.m_allThreadedPreProcessingPlanCommand.Count <= i_subtaskRank)
      return;
    this.m_allThreadedPreProcessingPlanCommand[i_subtaskRank].Cancel();
  }

  public override void Cancel()
  {
    this.PlanningWasCancelled = true;
    for (int index = 0; index < this.m_allThreadedPreProcessingPlanCommand.Count; ++index)
      this.m_allThreadedPreProcessingPlanCommand[index].Cancel();
    for (int index = 0; index < this.m_allThreadedPlanCommand.Count; ++index)
    {
      if (!this.m_allThreadedPlanCommand[index].IsFinished())
        this.m_allThreadedPlanCommand[index].Cancel();
    }
    if (this.m_subCycleTimeOpt == null)
      return;
    this.m_subCycleTimeOpt.Cancel();
  }

  private void OnMTTimer(object sender, EventArgs e)
  {
    bool flag1 = false;
    if (this.m_elapsedTimer.ElapsedMilliseconds - this.m_lastRefreshTime > 200L)
    {
      this.UpdateProgress(sender, e);
      this.m_lastRefreshTime = this.m_elapsedTimer.ElapsedMilliseconds;
    }
    if (this.PlanningWasCancelled)
    {
      for (int index = 0; index < this.m_runningThreadedPlanCommand.Count; ++index)
      {
        if (!this.m_runningThreadedPlanCommand[index].IsFinished())
          flag1 = true;
      }
      if (flag1)
        return;
      this.EndPlanning(true);
    }
    else
    {
      for (int index = 0; index < this.m_runningThreadedPlanCommand.Count; ++index)
      {
        if (this.m_runningThreadedPlanCommand[index].IsFinished())
        {
          if (this.m_runningPlanningThreads[index].IsAlive)
            this.m_runningPlanningThreads[index].Join();
          if (this.m_currentSubTaskIndex < this.m_allThreadedPlanCommand.Count - 1)
          {
            ++this.m_currentSubTaskIndex;
            this.m_runningPlanningThreads[index] = this.m_allPlanningThreads[this.m_currentSubTaskIndex];
            this.m_runningThreadedPlanCommand[index] = this.m_allThreadedPlanCommand[this.m_currentSubTaskIndex];
            this.m_runningPlanningThreads[index].Start();
            flag1 = true;
          }
        }
        else
          flag1 = true;
      }
      if (flag1)
        return;
      bool i_success = false;
      bool flag2 = false;
      for (int index = 0; index < this.m_allThreadedPlanCommand.Count; ++index)
      {
        i_success = i_success || this.m_allThreadedPlanCommand[index].WasPlanningSuccessful();
        flag2 = flag2 || !this.m_allThreadedPlanCommand[index].WasPlanningSuccessful() && !this.m_allThreadedPlanCommand[index].WasPlanningCancelled();
      }
      this.m_atLeastOneSuccess = i_success;
      this.m_atLeastOneError = flag2;
      this.EndPlanning(i_success);
    }
  }

  private void OnTimer(object sender, EventArgs e)
  {
    if (this.m_elapsedTimer.ElapsedMilliseconds - this.m_lastRefreshTime > 500L)
    {
      this.UpdateProgress(sender, e);
      this.m_lastRefreshTime = this.m_elapsedTimer.ElapsedMilliseconds;
    }
    this.HandlePlanningEvents();
    if (this.m_preProcessinRuning)
    {
      if (this.m_currentSubTaskIndex >= this.m_allThreadedPreProcessingPlanCommand.Count || !this.m_allThreadedPreProcessingPlanCommand[this.m_currentSubTaskIndex].IsFinished)
        return;
      bool flag = false;
      if (!this.PlanningWasCancelled)
      {
        this.StartNextPathPlanning(ref flag);
        if (!flag)
          return;
        this.EndPreProcessingPlanning(true, ref flag);
      }
      else
        this.EndPreProcessingPlanning(true, ref flag);
    }
    else
    {
      if (this.m_currentSubTaskIndex >= this.m_allThreadedPlanCommand.Count || !this.m_allThreadedPlanCommand[this.m_currentSubTaskIndex].IsFinished())
        return;
      this.m_atLeastOneSuccess = this.m_atLeastOneSuccess || this.m_allThreadedPlanCommand[this.m_currentSubTaskIndex].WasPlanningSuccessful();
      this.m_atLeastOneError = this.m_atLeastOneError || !this.m_allThreadedPlanCommand[this.m_currentSubTaskIndex].WasPlanningSuccessful() && !this.m_allThreadedPlanCommand[this.m_currentSubTaskIndex].WasPlanningCancelled();
      if (!this.PlanningWasCancelled)
      {
        bool o_trackEndReached = false;
        this.StartNextPathPlanning(ref o_trackEndReached);
        if (!o_trackEndReached)
          return;
        if (this.IsCycleTimeOptimizationOption() && this.m_optimize)
        {
          this.DoEndPlanning(this.m_atLeastOneSuccess);
          this.m_subCycleTimeOpt = new CApAPPOptimizeCycleTimeCommand(this.TasksToPlan, this.PathPlanningParams);
          this.m_subCycleTimeOpt.PlanningDidEnd += new PlanningDidEndEventHandler(this.OptCycleTime_PlanningDidEnd);
          this.m_subCycleTimeOpt.PlanningDidProgress += new PlanningDidProgressEventHandler(this.OptCycleTime_PlanningDidProgress);
          CApAPPPlanCommandBase.PlanSuccessEventArgs errEvtArgs = (CApAPPPlanCommandBase.PlanSuccessEventArgs) null;
          this.m_subCycleTimeOpt.Start(ref errEvtArgs);
        }
        else
          this.EndPlanning(this.m_atLeastOneSuccess);
      }
      else
        this.EndPlanning(true);
    }
  }

  private List<CApAPPWaypointPlanSuccess> GetTaskPlanSuccess(CApAPPTask task)
  {
    List<CApAPPWaypointPlanSuccess> taskPlanSuccess = new List<CApAPPWaypointPlanSuccess>();
    for (int i_index1 = 0; i_index1 < task.CountSubTasksToPlan(); ++i_index1)
    {
      int i_index2 = task.RetrieveWaypointIndexFromSubTask(task.SubTaskToPlan(i_index1));
      taskPlanSuccess.Add(task.Waypoint(i_index2).WaypointPlanSuccess);
    }
    return taskPlanSuccess;
  }

  private void DoEndPreProcessingPlanning(bool i_success)
  {
    this.m_preProcessinRuning = false;
    this.m_timer.Enabled = false;
    for (int index = 0; index < this.m_allPreProcessingPlanningThreads.Count; ++index)
    {
      if (this.m_allPreProcessingPlanningThreads[index].IsAlive)
        this.m_allPreProcessingPlanningThreads[index].Join();
    }
    this.m_waypointSavedAfterPreProcess = new List<CApAPPWaypoint>();
    for (int index = 0; index < this.TasksToPlan.Count; ++index)
    {
      List<CApAPPWaypointPlanSuccess> i_planSuccesses = new List<CApAPPWaypointPlanSuccess>();
      for (int i_subtaskRank = 0; i_subtaskRank < this.TasksToPlan[index].CountSubTasksToPlan(); ++i_subtaskRank)
      {
        CApAPPWaypointPlanSuccess processPlanSuccess = this.GetPreProcessPlanSuccess(i_subtaskRank);
        i_planSuccesses.Add(processPlanSuccess);
      }
      if (i_success)
        this.TasksToPlan[index].UpdateExternalAxis();
      List<CApAPPWaypoint> initialWaypoint = new List<CApAPPWaypoint>();
      this.m_waypointSavedAfterPreProcess = new List<CApAPPWaypoint>();
      for (int i_index = 0; i_index < this.TasksToPlan[index].Waypoints().Count; ++i_index)
      {
        initialWaypoint.Add(new CApAPPWaypoint(this.TasksToPlan[index].Waypoint(i_index)));
        this.m_waypointSavedAfterPreProcess.Add(new CApAPPWaypoint(this.TasksToPlan[index].Waypoint(i_index)));
      }
      this.TasksToPlan[index].UpdatePlanSuccesses(i_planSuccesses);
      this.TasksToPlan[index].UpdateWaypointsFromSubTasks();
      this.TasksToPlan[index].CountSubTasks();
      this.TasksToPlan[index].UpdateApproachDepartTxOperation(initialWaypoint);
    }
    this.m_allSubtasksToPlan = this.GetAllSubtasksToPlan();
    this.m_currentSubTaskIndex = -1;
    this.NotifyPlanningDidUpdate();
  }

  protected override bool IsPlanned(CApAPPSubTask subtask) => subtask.IsToPlan();

  private void DoEndPlanning(bool i_success)
  {
    this.m_timer.Enabled = false;
    for (int index = 0; index < this.m_allPlanningThreads.Count; ++index)
    {
      if (this.m_allPlanningThreads[index].IsAlive)
        this.m_allPlanningThreads[index].Join();
    }
    for (int index1 = 0; index1 < this.TasksToPlan.Count; ++index1)
    {
      int i_subtaskRank = 0;
      List<CApAPPWaypointPlanSuccess> taskPlanSuccess = this.GetTaskPlanSuccess(this.TasksToPlan[index1]);
      if (taskPlanSuccess.Count == this.TasksToPlan[index1].CountSubTasksToPlan())
      {
        for (int index2 = 0; index2 < this.TasksToPlan[index1].CountSubTasksToPlan(); ++index2)
        {
          if (this.IsPlanned(this.TasksToPlan[index1].SubTaskToPlan(index2)))
          {
            CApAPPWaypointPlanSuccess waypointPlanSuccess = this.GetPlanSuccess(i_subtaskRank);
            ++i_subtaskRank;
            if (waypointPlanSuccess == CApAPPWaypointPlanSuccess.WaitingBeforeCalc)
              waypointPlanSuccess = CApAPPWaypointPlanSuccess.Regular;
            taskPlanSuccess[index2] = waypointPlanSuccess;
          }
        }
      }
      if (i_success)
      {
        this.TasksToPlan[index1].UpdateWaypointsFromSubTasks();
        this.TasksToPlan[index1].UpdateTxOperation();
      }
      this.TasksToPlan[index1].UpdatePlanSuccesses(taskPlanSuccess);
      this.TasksToPlan[index1].RestoreInitialState();
    }
    if (this.m_allSubtasksToPlan.Last<CApAPPSubTask>().Task is CApAPPObjectFlowTask task)
      task.ResetGripPosition();
    TxApplication.RefreshDisplay();
  }

  private void EndPlanning(bool i_success)
  {
    this.DoEndPlanning(i_success);
    this.NotifyEndPlanning();
  }

  private void EndPreProcessingPlanning(bool i_success, ref bool taskPlanned)
  {
    this.DoEndPreProcessingPlanning(i_success);
    if (!this.PlanningWasCancelled)
    {
      if (this.StartNextPathPlanning(ref taskPlanned))
        return;
      this.EndPlanning(i_success);
    }
    else
      this.EndPlanning(i_success);
  }

  public override void UpdatePlanSuccesses()
  {
    for (int i_subtaskRank = 0; i_subtaskRank < this.CountSubProblems(); ++i_subtaskRank)
      this.UpdateWaypointPlanSuccess(i_subtaskRank);
    this.NotifyUpdateWaypointStatus();
  }

  private void HandlePlanningEvents()
  {
    if (this.m_currentSubTaskIndex >= this.m_allSubtasksToPlan.Count || !(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].Task is CApAPPObjectFlowTask) || !this.m_mustShowLastAddedPosition)
      return;
    CApAPPObjectFlowTask task = this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].Task as CApAPPObjectFlowTask;
    KiAppLocationEx kiAppLocationEx = (KiAppLocationEx) null;
    KiAppSegmentPlanCommandEx.GetLastAddedNode(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].KiSubTask, ref kiAppLocationEx);
    if (kiAppLocationEx == null)
      return;
    task.SetGripLocation(new TxTransformation(kiAppLocationEx.AbsoluteLocation));
    TxApplication.RefreshDisplay();
  }

  public override CApAPPWaypointPlanSuccess GetPlanSuccess(int i_subtaskRank)
  {
    CApAPPWaypointPlanSuccess planSuccess = CApAPPWaypointPlanSuccess.WaitingBeforeCalc;
    if (i_subtaskRank <= this.m_currentSubTaskIndex)
    {
      switch (!this.m_preProcessinRuning ? this.m_allThreadedPlanCommand[i_subtaskRank].PlanSuccess() : this.m_allThreadedPreProcessingPlanCommand[i_subtaskRank].PlanSuccess())
      {
        case CApAPPPlanSuccess.SUCCESS:
          planSuccess = CApAPPWaypointPlanSuccess.CalcSuccess;
          break;
        case CApAPPPlanSuccess.SKIP:
          planSuccess = CApAPPWaypointPlanSuccess.Cancel;
          break;
        case CApAPPPlanSuccess.CLASH_ERROR:
          planSuccess = (CApAPPWaypointPlanSuccess) KiAppSegmentPlanCommandEx.GetPlanSuccess(this.m_allSubtasksToPlan[i_subtaskRank].KiSubTask);
          break;
        case CApAPPPlanSuccess.TIMEOUT_ERROR:
          planSuccess = CApAPPWaypointPlanSuccess.CalcFail;
          break;
        case CApAPPPlanSuccess.WAIT:
          planSuccess = CApAPPWaypointPlanSuccess.WaitingForCalc;
          break;
        case CApAPPPlanSuccess.WAIT_BEFORE_START:
          planSuccess = CApAPPWaypointPlanSuccess.WaitingBeforeCalc;
          break;
        case CApAPPPlanSuccess.SUCCESS_PREPROCESSING:
          planSuccess = CApAPPWaypointPlanSuccess.PreProcessingSuccess;
          break;
      }
    }
    else if (this.m_preProcessing && i_subtaskRank < this.m_allSubtasksToPlan.Count && this.m_waypointSavedAfterPreProcess != null)
    {
      for (int index = 0; index < this.m_waypointSavedAfterPreProcess.Count; ++index)
      {
        if (this.m_waypointSavedAfterPreProcess[index] != null && this.m_waypointSavedAfterPreProcess[index].IsSimular(this.m_allSubtasksToPlan[i_subtaskRank].LastWaypoint()))
        {
          planSuccess = this.m_waypointSavedAfterPreProcess[index].WaypointPlanSuccess;
          break;
        }
      }
    }
    return planSuccess;
  }

  public CApAPPWaypointPlanSuccess GetPreProcessPlanSuccess(int i_subtaskRank)
  {
    CApAPPWaypointPlanSuccess processPlanSuccess = CApAPPWaypointPlanSuccess.WaitingBeforeCalc;
    if (i_subtaskRank <= this.m_currentSubTaskIndex)
    {
      processPlanSuccess = CApAPPWaypointPlanSuccess.Regular;
      if (this.m_allThreadedPreProcessingPlanCommand[i_subtaskRank].PlanSuccess() == CApAPPPlanSuccess.SUCCESS_PREPROCESSING)
        processPlanSuccess = CApAPPWaypointPlanSuccess.PreProcessingSuccess;
    }
    return processPlanSuccess;
  }

  public override long GetElapsedTime() => this.m_elapsedTimer.ElapsedMilliseconds;

  public bool GetPlanningStatus(int i_subtaskRank)
  {
    bool planningStatus = false;
    if (i_subtaskRank <= this.m_currentSubTaskIndex)
      planningStatus = !this.m_allThreadedPlanCommand[i_subtaskRank].IsFinished();
    return planningStatus;
  }

  public override bool IsFinished(int i_subtaskRank)
  {
    bool flag = false;
    if (!this.m_preProcessinRuning)
    {
      if (i_subtaskRank <= this.m_currentSubTaskIndex)
        flag = this.m_allThreadedPlanCommand[i_subtaskRank].IsFinished();
    }
    else if (i_subtaskRank <= this.m_currentSubTaskIndex)
      flag = this.m_allThreadedPreProcessingPlanCommand[i_subtaskRank].IsFinished;
    return flag;
  }

  public override double GetProgress()
  {
    double num1 = 0.0;
    double num2 = (double) this.CountPlanSubTasks();
    double progress;
    if (this.m_preProcessinRuning)
    {
      for (int index = 0; index < this.m_currentSubTaskIndex; ++index)
        num1 += 1.0 / num2;
      progress = (num1 + this.GetProgress(this.m_currentSubTaskIndex) / num2) * 0.25;
    }
    else
    {
      for (int index = 0; index < this.m_currentSubTaskIndex; ++index)
        num1 += 1.0 / num2;
      progress = num1 + this.GetProgress(this.m_currentSubTaskIndex) / num2;
      if (this.m_preProcessing)
        progress = 0.25 + progress * 0.75;
    }
    if (this.m_subCycleTimeOpt != null)
      progress += this.m_subCycleTimeOpt.GetProgress();
    if (this.IsCycleTimeOptimizationOption() && this.m_optimize)
      progress /= 2.0;
    return progress;
  }

  public override double GetProgress(int i_subtaskRank)
  {
    double progress = 0.0;
    if (i_subtaskRank <= this.m_currentSubTaskIndex && i_subtaskRank < this.m_allThreadedPlanCommand.Count)
      progress = this.m_allThreadedPlanCommand[i_subtaskRank].GetProgress();
    return progress;
  }

  public double GetPreProcessingProgress(int i_subtaskRank)
  {
    double processingProgress = 0.0;
    if (i_subtaskRank <= this.m_currentSubTaskIndex && i_subtaskRank < this.m_allThreadedPreProcessingPlanCommand.Count)
      processingProgress = this.m_allThreadedPreProcessingPlanCommand[i_subtaskRank].GetProgress();
    return processingProgress;
  }

  public override void UpdateWaypointPlanSuccess(int i_subtaskRank)
  {
    if (i_subtaskRank >= this.m_allSubtasksToPlan.Count)
      return;
    CApAPPTask capAppTask = CApAPPTask.RetrieveSubTaskParentTask(this.m_allSubtasksToPlan[i_subtaskRank], this.TasksToPlan);
    if (capAppTask == null)
      return;
    int i_index = capAppTask.RetrieveWaypointIndexFromSubTask(this.m_allSubtasksToPlan[i_subtaskRank]);
    int num;
    switch (capAppTask.Waypoint(i_index).WaypointPlanSuccess)
    {
      case CApAPPWaypointPlanSuccess.Collision:
      case CApAPPWaypointPlanSuccess.SectionVolumeCollision:
      case CApAPPWaypointPlanSuccess.LocReachFail:
      case CApAPPWaypointPlanSuccess.OutOfLimits:
      case CApAPPWaypointPlanSuccess.TwistedCable:
      case CApAPPWaypointPlanSuccess.SingularityZone:
      case CApAPPWaypointPlanSuccess.PreProcessingSuccess:
        num = 0;
        break;
      default:
        num = capAppTask.Waypoint(i_index).WaypointStatus != CApAPPWaypointStatus.ReachFail ? 1 : 0;
        break;
    }
    if (num != 0)
    {
      capAppTask.Waypoint(i_index).WaypointPlanSuccess = this.GetPlanSuccess(i_subtaskRank);
    }
    else
    {
      if (capAppTask.Waypoint(i_index).WaypointStatus != CApAPPWaypointStatus.ReachFail)
        return;
      capAppTask.Waypoint(i_index).WaypointPlanSuccess = CApAPPWaypointPlanSuccess.LocReachFail;
    }
  }

  private void OptCycleTime_PlanningDidProgress(object sender, EventArgs e)
  {
    this.UpdateProgress(sender, e);
  }

  private void OptCycleTime_PlanningDidEnd(
    object sender,
    CApAPPPlanCommandBase.PlanSuccessEventArgs e)
  {
    CApAPPPlanCommandBase appPlanCommandBase = sender as CApAPPPlanCommandBase;
    bool i_success = this.WasPlanningProcessSuccessful();
    string i_details = this.ComputeErrorMessage();
    string i_message = CApAPPMainWindowStringTable.PathPlanningErrorTitle;
    if (this.WasPlanningProcessSuccessful() && !e.Successful)
    {
      i_success = false;
      i_message = e.ErrorMessage;
      i_details = e.ErrorDetails;
    }
    this.NotifyEndPlanning((object) this, new CApAPPPlanCommandBase.PlanSuccessEventArgs(i_success, i_message, i_details));
  }

  private void NotifyEndPlanning()
  {
    this.NotifyEndPlanning((object) this, new CApAPPPlanCommandBase.PlanSuccessEventArgs(this.WasPlanningProcessSuccessful(), CApAPPMainWindowStringTable.PathPlanningErrorTitle, this.ComputeErrorMessage()));
  }

  public bool WasPlanningProcessSuccessful()
  {
    return !this.m_atLeastOneError || this.PlanningWasCancelled || this.m_planningWasSkipped;
  }

  public string ComputeErrorMessage()
  {
    return $"{CApAPPMainWindowStringTable.PathPlanningErrorMsg}\r\n{CApAPPMainWindowStringTable.PathPlanningErrorCheckLocationStatusMsg}";
  }

  internal override bool IsMagnetPointEnabled()
  {
    return this.m_magnetPoint != null && this.m_magnetPoint.IsActivated();
  }

  internal override void ToggleMagnetPoint()
  {
    if (this.IsMagnetPointEnabled())
    {
      this.m_magnetPoint.Deactivate();
    }
    else
    {
      CApAPPSubTask capAppSubTask = this.m_allSubtasksToPlan[this.m_currentSubTaskIndex];
      if (!(capAppSubTask.Task is CApAPPObjectFlowTask))
        return;
      if (this.m_magnetPoint == null)
      {
        try
        {
          this.m_magnetPoint = new CApAPPMagnetPoint(capAppSubTask.Task as CApAPPObjectFlowTask);
        }
        catch (CApAPPMagnetPoint.MagnetPointCreationFailedException ex)
        {
          this.m_magnetPoint = (CApAPPMagnetPoint) null;
        }
      }
      if (this.m_magnetPoint != null)
        this.m_magnetPoint.Activate();
      this.SetMagnetPointPositionToStartPosition();
    }
  }

  internal override void ClearMagnetPoint()
  {
    if (this.m_magnetPoint == null)
      return;
    this.m_magnetPoint.Deactivate();
    this.m_magnetPoint.ClearData();
    this.m_magnetPoint = (CApAPPMagnetPoint) null;
  }

  internal override void SetMagnetPointPositionToLastAddedNode()
  {
    if (this.m_magnetPoint == null)
      return;
    KiAppLocationEx kiAppLocationEx = (KiAppLocationEx) null;
    KiAppSegmentPlanCommandEx.GetLastAddedNode(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].KiSubTask, ref kiAppLocationEx);
    if (kiAppLocationEx == null)
      return;
    this.m_magnetPoint.SetPosition(new TxTransformation(kiAppLocationEx.AbsoluteLocation));
  }

  internal void SetMagnetPointPositionToStartPosition()
  {
    if (this.m_magnetPoint == null)
      return;
    this.m_magnetPoint.SetPosition(new TxTransformation(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].Task.Waypoint(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].KiSubTask.SourceWaypointIndex).SimulatedApproachLocation.AbsoluteLocation));
  }

  internal override KiAppPlanningStep GetCurrentPlanningStep()
  {
    KiAppPlanningStep currentPlanningStep = (KiAppPlanningStep) 0;
    if (this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count)
      currentPlanningStep = KiAppSegmentPlanCommandEx.GetCurrentPlanningStep(this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].KiSubTask);
    return currentPlanningStep;
  }

  internal override void EnableShowLastAddedPosition() => this.m_mustShowLastAddedPosition = true;

  internal override void DisableShowLastAddedPosition()
  {
    if (this.m_currentSubTaskIndex < this.m_allSubtasksToPlan.Count && this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].Task is CApAPPObjectFlowTask)
    {
      (this.m_allSubtasksToPlan[this.m_currentSubTaskIndex].Task as CApAPPObjectFlowTask).ResetGripPosition();
      TxApplication.RefreshDisplay();
    }
    this.m_mustShowLastAddedPosition = false;
  }

  internal override void AfterPlanningFailure()
  {
    if (this.m_subCycleTimeOpt == null)
      return;
    this.m_subCycleTimeOpt.AfterPlanningFailure();
  }

  protected bool IsCycleTimeOptimizationOption()
  {
    return this.PathPlanningParams.OptimizationOption == 2 || this.PathPlanningParams.OptimizationOption == 3;
  }
}
